#pragma once
#include "Types/AtomicType.h"
#include "Types/ArrowType.h"
#include "Types/AbstractType.h"
#include "Terms/TermVariable.h"
#include "Terms/ApplicationTerm.h"
#include "Terms/AbstractTerm.h"
#include "Terms/AbstractTypeTerm.h"
#include "../Math/EvaluatingFunction.h"

#include <vector>
#include <map>
using namespace std;


class TokenSet{

public:
	typedef TokenSet* pointer;

protected:
	size_t vecSize;

public:
	typedef vector<Token::pointer> vecTokenPtr;
	typedef map<size_t , vecTokenPtr>::const_iterator PartitionIterator;
	typedef Token::exception exception;

protected:
	void copyMap(const TokenSet&);
	void destroyMap();
	map<size_t , vecTokenPtr> Partition;

public:
	TokenSet( );
	TokenSet(const TokenSet&);
	virtual ~TokenSet();
	
public:
	 virtual const Token* getRandToken() const;
	 PartitionIterator beginMinimumComplexity(size_t) const;
	 virtual size_t totalComplexity( ) const;

public:
	virtual Token::const_reference operator[ ](size_t) const;
		
public:
    virtual const				Token*	find(Token::const_reference) const; 
	virtual const				Token*	insert(Token::const_reference);
	virtual void					insertSet(const TokenSet&);
	virtual bool  				remove(Token::const_reference);


public:
	virtual const TokenSet& operator=(const TokenSet&);
	virtual size_t size() const;
	virtual string toString()const;

public:
	static TokenSet* freeVariablesof(const Term& );
	static TokenSet* allFreeAtomicTypesof(const Token&);
	};



class TermSet : public TokenSet{
 
public:
	TokenSet   Types;
    
public:
	size_t TySize()const{return Types.size();};
	size_t TeSize()const{return size();};
  
public:
	TermSet( );
	TermSet(const TermSet&);

public:
	bool hasType(Type::const_reference) const;
	bool hasTerm(Term::const_reference) const;

public:
	const Token* insert(Token::const_reference);
	string toString()const;
	const Token* find(Token::const_reference) const;
	size_t totalComplexity( ) const;

public:
	const Token*  getRandToken() const;
	const Term*   getRandTerm() const;	 
	const Type*	getRandType() const;
	const Term*   getRandTermOfType(Type::const_reference) const;
	const Term*   getRandFunctionInDomain(Type::const_reference) const;
	const Term*   getRandFunctionToDomain(Type::const_reference) const; 
};



class SemanticEvaluation : public pair<Token*,  FTypeName<double>* >{

public:
		SemanticEvaluation( );
		SemanticEvaluation( Token*,  FTypeName<double>* );
		SemanticEvaluation( const SemanticEvaluation& );
		
		const SemanticEvaluation& operator=(const SemanticEvaluation&);
		bool isNull( ) const {return (first || second)? true:false;};
		~SemanticEvaluation( );

public:

		SemanticEvaluation* SemanticPlus( SemanticEvaluation* );
		SemanticEvaluation* SemanticDiv( SemanticEvaluation*);
		SemanticEvaluation* SemanticMinus( SemanticEvaluation* );
		SemanticEvaluation* SemanticMult( SemanticEvaluation* );
		SemanticEvaluation* SemanticGt( SemanticEvaluation* );
	
	
	};


class EvaluatingTermSet : public TermSet{

protected:
	vector<const Token*> Primitives;
	size_t* maxComplexity;

public:
	bool isPrimitive(const Token&) const;
	void setAsPrimitive(const Token&);

private:
	typedef map<const Term*,  SemanticEvaluation*> SemanticEnvironment;
	SemanticEnvironment SEnv;

protected:
	void	setValue (const Term* To, SemanticEvaluation* SE);
	virtual const SemanticEvaluation* getValue (const Term*) const;
	virtual const Token* insert(Token::const_reference);
	};









